package com.gitee.wsl.mathematics.geometry.d2


import com.gitee.wsl.mathematics.geometry.d2.base.YPolarity
import com.gitee.wsl.mathematics.geometry.d2.circle.Circle
import com.gitee.wsl.mathematics.geometry.d2.contour.ShapeContour
import com.gitee.wsl.mathematics.geometry.d2.contour.segment.Segment2D
import com.gitee.wsl.mathematics.vector.ext.distanceTo
import com.gitee.wsl.mathematics.vector.vec2.Vec2f
import kotlin.test.*

// TODO: Move this to a dedicated package
internal fun assertEquals(expected: Vec2f, actual: Vec2f, absoluteTolerance: Double, message: String? = null) {
    //assertEquals(expected.x, actual.x, absoluteTolerance, message)
    //assertEquals(expected.y, actual.y, absoluteTolerance, message)
}

class ShapeContourTest {


    @Test
    fun shouldCalculateAdaptivePositionsWithT() {
        val c = Circle(0.0, 0.0, 200.0).contour
        val points = c.adaptivePositionsWithT()
        assertEquals(0.0, points.first().second)
        for (i in points.indices) {
            val tp = c.position(points[i].second.toFloat())
            assertTrue(tp.distanceTo(points[i].first) < 0.05)
        }
    }

    @Test
    fun shouldCalculateEquidistantPositionsWithT() {
        val c = Circle(0.0, 0.0, 200.0).contour
        val points = c.equidistantPositionsWithT(20)
        assertEquals(0.0, points.first().second)
        for (i in points.indices) {
            val tp = c.position(points[i].second.toFloat())
            assertTrue(tp.distanceTo(points[i].first) < 0.05)
        }

    }

    @Test
    fun shouldCalculateTValues() {
        val positionsWithT = Circle(0.0, 0.0, 200.0).contour.adaptivePositionsWithT()
        assertEquals(0.0, positionsWithT.first().second)
        assertEquals(1.0, positionsWithT.last().second)
    }

    @Test
    fun shouldCalculateSimplePointAtLength() {
        val rectangleContour = ShapeContour(
            listOf(
                Segment2D(Vec2f(7.0, 6.0), Vec2f(507.0, 6.0)),
                Segment2D(Vec2f(507.0, 6.0), Vec2f(507.0, 506.0)),
                Segment2D(Vec2f(507.0, 506.0), Vec2f(7.0, 506.0)),
                Segment2D(Vec2f(7.0, 506.0), Vec2f(7.0, 6.0))
            ), true, YPolarity.CW_NEGATIVE_Y
        )
        assertEquals(Vec2f(507.0, 16.0), rectangleContour.pointAtLength(510.0f, 0.0001))

        val curveContour = ShapeContour(
            listOf(
                Segment2D(Vec2f(110.0, 150.0), Vec2f(25.0, 190.0), Vec2f(210.0, 250.0), Vec2f(210.0, 30.0))
            ), false, YPolarity.CW_NEGATIVE_Y
        )
        assertEquals(Vec2f(105.53567504882812, 152.2501678466797), curveContour.pointAtLength(5.0f, 0.0001), 0.001)
        assertEquals(Vec2f(162.22564697265625, 170.3757781982422), curveContour.pointAtLength(120.0f, 0.0001), 0.001)
        assertEquals(curveContour.segments.first().start, curveContour.pointAtLength(-500.0f, 0.0001))
        assertEquals(curveContour.segments.first().end, curveContour.pointAtLength(500.0f, 0.0001))
    }

    @Test
    fun shouldCalculateComplexPointAtLength() {
        val poorlyDrawnLine = ShapeContour(
            listOf(
                Segment2D(Vec2f(11.41, 164.15), listOf(Vec2f(11.41, 164.15)), Vec2f(11.03, 159.44)),
                Segment2D(Vec2f(11.03, 159.44), listOf(Vec2f(10.65, 154.74)), Vec2f(9.57, 148.84)),
                Segment2D(Vec2f(9.57, 148.84), listOf(Vec2f(8.48, 142.95)), Vec2f(7.0, 136.78)),
                Segment2D(Vec2f(7.0, 136.78), listOf(Vec2f(5.52, 130.6)), Vec2f(4.25, 124.7)),
                Segment2D(Vec2f(4.25, 124.7), listOf(Vec2f(2.98, 118.79)), Vec2f(2.06, 113.27)),
                Segment2D(Vec2f(2.06, 113.27), listOf(Vec2f(1.14, 107.75)), Vec2f(0.63, 102.66)),
                Segment2D(Vec2f(0.63, 102.66), listOf(Vec2f(0.12, 97.57)), Vec2f(-0.15, 92.97)),
                Segment2D(Vec2f(-0.15, 92.97), listOf(Vec2f(-0.43, 88.37)), Vec2f(-0.58, 83.36)),
                Segment2D(Vec2f(-0.58, 83.36), listOf(Vec2f(-0.73, 78.35)), Vec2f(-0.36, 73.52)),
                Segment2D(Vec2f(-0.36, 73.52), listOf(Vec2f(-0.0, 68.69)), Vec2f(0.65, 64.22)),
                Segment2D(Vec2f(0.65, 64.22), listOf(Vec2f(1.31, 59.76)), Vec2f(3.05, 55.61)),
                Segment2D(Vec2f(3.05, 55.61), listOf(Vec2f(4.79, 51.47)), Vec2f(7.35, 47.81)),
                Segment2D(Vec2f(7.35, 47.81), listOf(Vec2f(9.91, 44.15)), Vec2f(12.9, 40.79)),
                Segment2D(Vec2f(12.9, 40.79), listOf(Vec2f(15.89, 37.44)), Vec2f(19.32, 33.81)),
                Segment2D(Vec2f(19.32, 33.81), listOf(Vec2f(22.76, 30.18)), Vec2f(27.36, 25.92)),
                Segment2D(Vec2f(27.36, 25.92), listOf(Vec2f(31.96, 21.66)), Vec2f(37.91, 17.69)),
                Segment2D(Vec2f(37.91, 17.69), listOf(Vec2f(43.87, 13.73)), Vec2f(50.78, 10.64)),
                Segment2D(Vec2f(50.78, 10.64), listOf(Vec2f(57.69, 7.54)), Vec2f(65.58, 5.6)),
                Segment2D(Vec2f(65.58, 5.6), listOf(Vec2f(73.47, 3.66)), Vec2f(81.19, 2.59)),
                Segment2D(Vec2f(81.19, 2.59), listOf(Vec2f(88.92, 1.53)), Vec2f(95.64, 0.94)),
                Segment2D(Vec2f(95.64, 0.94), listOf(Vec2f(102.36, 0.35)), Vec2f(107.91, 0.48)),
                Segment2D(Vec2f(107.91, 0.48), listOf(Vec2f(113.46, 0.6)), Vec2f(116.95, 0.67)),
                Segment2D(Vec2f(116.95, 0.67), listOf(Vec2f(120.44, 0.74)), Vec2f(123.2, 1.71)),
                Segment2D(Vec2f(123.2, 1.71), listOf(Vec2f(125.97, 2.67)), Vec2f(128.65, 4.6)),
                Segment2D(Vec2f(128.65, 4.6), listOf(Vec2f(131.33, 6.53)), Vec2f(133.46, 8.49)),
                Segment2D(Vec2f(133.46, 8.49), listOf(Vec2f(135.59, 10.45)), Vec2f(138.23, 13.9)),
                Segment2D(Vec2f(138.23, 13.9), listOf(Vec2f(140.86, 17.34)), Vec2f(140.94, 17.49)),
                Segment2D(Vec2f(140.94, 17.49), listOf(Vec2f(141.02, 17.65)), Vec2f(141.05, 17.82)),
                Segment2D(Vec2f(141.05, 17.82), listOf(Vec2f(141.08, 17.99)), Vec2f(141.05, 18.17)),
                Segment2D(Vec2f(141.05, 18.17), listOf(Vec2f(141.02, 18.34)), Vec2f(140.94, 18.5)),
                Segment2D(Vec2f(140.94, 18.5), listOf(Vec2f(140.86, 18.65)), Vec2f(140.73, 18.77)),
                Segment2D(Vec2f(140.73, 18.77), listOf(Vec2f(140.61, 18.89)), Vec2f(140.45, 18.97)),
                Segment2D(Vec2f(140.45, 18.97), listOf(Vec2f(140.29, 19.04)), Vec2f(140.11, 19.06)),
                Segment2D(Vec2f(140.11, 19.06), listOf(Vec2f(139.94, 19.08)), Vec2f(139.77, 19.04)),
                Segment2D(Vec2f(139.77, 19.04), listOf(Vec2f(139.59, 19.0)), Vec2f(139.44, 18.91)),
                Segment2D(Vec2f(139.44, 18.91), listOf(Vec2f(139.29, 18.82)), Vec2f(139.18, 18.69)),
                Segment2D(Vec2f(139.18, 18.69), listOf(Vec2f(139.07, 18.56)), Vec2f(139.0, 18.39)),
                Segment2D(Vec2f(139.0, 18.39), listOf(Vec2f(138.93, 18.23)), Vec2f(138.93, 18.05)),
                Segment2D(Vec2f(138.93, 18.05), listOf(Vec2f(138.92, 17.88)), Vec2f(138.96, 17.71)),
                Segment2D(Vec2f(138.96, 17.71), listOf(Vec2f(139.01, 17.54)), Vec2f(139.11, 17.39)),
                Segment2D(Vec2f(139.11, 17.39), listOf(Vec2f(139.21, 17.25)), Vec2f(139.35, 17.14)),
                Segment2D(Vec2f(139.35, 17.14), listOf(Vec2f(139.49, 17.04)), Vec2f(139.65, 16.98)),
                Segment2D(Vec2f(139.65, 16.98), listOf(Vec2f(139.82, 16.92)), Vec2f(139.99, 16.92)),
                Segment2D(Vec2f(139.99, 16.92), listOf(Vec2f(140.17, 16.92)), Vec2f(140.34, 16.98)),
                Segment2D(Vec2f(140.34, 16.98), listOf(Vec2f(140.5, 17.04)), Vec2f(140.64, 17.14)),
                Segment2D(Vec2f(140.64, 17.14), listOf(Vec2f(140.78, 17.25)), Vec2f(140.88, 17.39)),
                Segment2D(Vec2f(140.88, 17.39), listOf(Vec2f(140.98, 17.54)), Vec2f(141.03, 17.71)),
                Segment2D(Vec2f(141.03, 17.71), listOf(Vec2f(141.07, 17.88)), Vec2f(141.07, 18.05)),
                Segment2D(Vec2f(141.07, 18.05), listOf(Vec2f(141.06, 18.23)), Vec2f(140.99, 18.39)),
                Segment2D(Vec2f(140.99, 18.39), listOf(Vec2f(140.93, 18.55)), Vec2f(140.81, 18.69)),
                Segment2D(Vec2f(140.81, 18.69), listOf(Vec2f(140.7, 18.82)), Vec2f(140.55, 18.91)),
                Segment2D(Vec2f(140.55, 18.91), listOf(Vec2f(140.4, 19.0)), Vec2f(140.23, 19.04)),
                Segment2D(Vec2f(140.23, 19.04), listOf(Vec2f(140.05, 19.08)), Vec2f(139.88, 19.06)),
                Segment2D(Vec2f(139.88, 19.06), listOf(Vec2f(139.71, 19.04)), Vec2f(139.55, 18.97)),
                Segment2D(Vec2f(139.55, 18.97), listOf(Vec2f(139.39, 18.89)), Vec2f(139.26, 18.77)),
                Segment2D(Vec2f(139.26, 18.77), listOf(Vec2f(139.13, 18.65)), Vec2f(139.13, 18.65)),
                Segment2D(Vec2f(139.13, 18.65), listOf(Vec2f(139.13, 18.65)), Vec2f(136.62, 15.35)),
                Segment2D(Vec2f(136.62, 15.35), listOf(Vec2f(134.12, 12.05)), Vec2f(132.09, 10.17)),
                Segment2D(Vec2f(132.09, 10.17), listOf(Vec2f(130.05, 8.28)), Vec2f(127.63, 6.5)),
                Segment2D(Vec2f(127.63, 6.5), listOf(Vec2f(125.21, 4.71)), Vec2f(122.79, 3.81)),
                Segment2D(Vec2f(122.79, 3.81), listOf(Vec2f(120.36, 2.91)), Vec2f(116.89, 2.84)),
                Segment2D(Vec2f(116.89, 2.84), listOf(Vec2f(113.41, 2.77)), Vec2f(107.98, 2.64)),
                Segment2D(Vec2f(107.98, 2.64), listOf(Vec2f(102.55, 2.52)), Vec2f(95.88, 3.1)),
                Segment2D(Vec2f(95.88, 3.1), listOf(Vec2f(89.21, 3.68)), Vec2f(81.6, 4.72)),
                Segment2D(Vec2f(81.6, 4.72), listOf(Vec2f(73.99, 5.77)), Vec2f(66.28, 7.65)),
                Segment2D(Vec2f(66.28, 7.65), listOf(Vec2f(58.57, 9.53)), Vec2f(51.82, 12.54)),
                Segment2D(Vec2f(51.82, 12.54), listOf(Vec2f(45.07, 15.55)), Vec2f(39.25, 19.4)),
                Segment2D(Vec2f(39.25, 19.4), listOf(Vec2f(33.44, 23.26)), Vec2f(28.89, 27.47)),
                Segment2D(Vec2f(28.89, 27.47), listOf(Vec2f(24.34, 31.68)), Vec2f(20.93, 35.29)),
                Segment2D(Vec2f(20.93, 35.29), listOf(Vec2f(17.53, 38.89)), Vec2f(14.62, 42.15)),
                Segment2D(Vec2f(14.62, 42.15), listOf(Vec2f(11.7, 45.41)), Vec2f(9.26, 48.87)),
                Segment2D(Vec2f(9.26, 48.87), listOf(Vec2f(6.81, 52.33)), Vec2f(5.15, 56.21)),
                Segment2D(Vec2f(5.15, 56.21), listOf(Vec2f(3.49, 60.09)), Vec2f(2.85, 64.48)),
                Segment2D(Vec2f(2.85, 64.48), listOf(Vec2f(2.22, 68.86)), Vec2f(1.86, 73.57)),
                Segment2D(Vec2f(1.86, 73.57), listOf(Vec2f(1.51, 78.28)), Vec2f(1.67, 83.26)),
                Segment2D(Vec2f(1.67, 83.26), listOf(Vec2f(1.84, 88.23)), Vec2f(2.13, 92.78)),
                Segment2D(Vec2f(2.13, 92.78), listOf(Vec2f(2.43, 97.34)), Vec2f(2.95, 102.34)),
                Segment2D(Vec2f(2.95, 102.34), listOf(Vec2f(3.48, 107.35)), Vec2f(4.43, 112.81)),
                Segment2D(Vec2f(4.43, 112.81), listOf(Vec2f(5.38, 118.26)), Vec2f(6.7, 124.13)),
                Segment2D(Vec2f(6.7, 124.13), listOf(Vec2f(8.01, 129.99)), Vec2f(9.58, 136.21)),
                Segment2D(Vec2f(9.58, 136.21), listOf(Vec2f(11.15, 142.44)), Vec2f(12.35, 148.45)),
                Segment2D(Vec2f(12.35, 148.45), listOf(Vec2f(13.55, 154.46)), Vec2f(14.07, 159.15)),
                Segment2D(Vec2f(14.07, 159.15), listOf(Vec2f(14.58, 163.84)), Vec2f(14.58, 164.04)),
                Segment2D(Vec2f(14.58, 164.04), listOf(Vec2f(14.57, 164.23)), Vec2f(14.52, 164.41)),
                Segment2D(Vec2f(14.52, 164.41), listOf(Vec2f(14.47, 164.6)), Vec2f(14.38, 164.77)),
                Segment2D(Vec2f(14.38, 164.77), listOf(Vec2f(14.28, 164.93)), Vec2f(14.15, 165.07)),
                Segment2D(Vec2f(14.15, 165.07), listOf(Vec2f(14.02, 165.21)), Vec2f(13.86, 165.32)),
                Segment2D(Vec2f(13.86, 165.32), listOf(Vec2f(13.7, 165.42)), Vec2f(13.52, 165.49)),
                Segment2D(Vec2f(13.52, 165.49), listOf(Vec2f(13.34, 165.55)), Vec2f(13.14, 165.57)),
                Segment2D(Vec2f(13.14, 165.57), listOf(Vec2f(12.95, 165.59)), Vec2f(12.76, 165.56)),
                Segment2D(Vec2f(12.76, 165.56), listOf(Vec2f(12.57, 165.53)), Vec2f(12.4, 165.46)),
                Segment2D(Vec2f(12.4, 165.46), listOf(Vec2f(12.22, 165.39)), Vec2f(12.06, 165.27)),
                Segment2D(Vec2f(12.06, 165.27), listOf(Vec2f(11.91, 165.16)), Vec2f(11.78, 165.01)),
                Segment2D(Vec2f(11.78, 165.01), listOf(Vec2f(11.66, 164.87)), Vec2f(11.58, 164.69)),
                Segment2D(Vec2f(11.58, 164.69), listOf(Vec2f(11.49, 164.52)), Vec2f(11.45, 164.33)),
                Segment2D(Vec2f(11.45, 164.33), listOf(), Vec2f(11.41, 164.15))
            ), false, YPolarity.CW_NEGATIVE_Y
        )

        val point = poorlyDrawnLine.pointAtLength(100.0f, 0.0001)
        // These are the coordinates which Firefox 103 reports for an equivalent SVG and they
        // seem to be consistent across browsers with a tolerance as low as 0.0001.
        assertEquals(Vec2f(0.5043081045150757, 65.25358581542969), point, 0.005)
    }
}